// Copyright 2017 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the “License”); you may not use this file except in
// compliance with the License.  You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
/////////////////////////////////////////////////////////
// includes
/////////////////////////////////////////////////////////
#include "mlButter.h"
#include "math_fns.h"
#include "bar.h"
#include "utils.h"
#include "bench.h"

/////////////////////////////////////////////////////////
// shared globals
/////////////////////////////////////////////////////////


  __attribute__ ((section(".heapsram"))) static const float fv0[800] = { 0.0814449489F, 0.541797936F, -0.0551075488F,
    0.0269560963F, 2.75604892F, -1.31419647F, 0.743531525F, 1.57619083F,
    1.17270935F, 0.624531686F, 0.593503177F, 2.33901286F, -0.624484658F,
    1.35942F, 0.640898228F, 2.33339477F, 0.552029133F, -0.651669145F,
    0.896165371F, 0.581846952F, 1.31055176F, 0.165580705F, -0.942066848F,
    -0.0873283818F, 1.5072037F, -1.33596969F, -1.15924442F, 1.18487F,
    -1.84924841F, -0.376697898F, -0.340449721F, -0.999949753F, -1.75592768F,
    -0.567810476F, -0.651007F, -0.708271742F, -1.04721296F, -2.2981081F,
    0.116752237F, -0.593765438F, -1.22705305F, -0.979483664F, 0.202293664F,
    -0.96288377F, -0.278580695F, -1.36410761F, 1.89158666F, -1.23878431F,
    -0.0649931F, 0.905137062F, 0.177448094F, 0.883569419F, 0.0251957048F,
    0.341300488F, 1.01618195F, 2.00272226F, 0.0268944763F, 1.35262859F,
    -0.0496077F, 1.70757723F, 1.24130869F, 0.666073918F, 1.43157387F,
    0.218539104F, 0.681122363F, 1.16112041F, 0.220985532F, 0.81591469F,
    1.1473906F, -0.76069814F, -0.117658913F, -0.568115473F, 1.91249156F,
    -0.939186394F, -0.628127038F, -0.84525454F, -1.16859245F, 0.142757758F,
    0.0312339254F, -1.86965263F, -1.20913208F, -0.205374137F, -1.45187938F,
    -1.36163104F, -0.343834132F, -0.860210598F, -0.760624945F, -1.78840399F,
    -0.769037545F, 0.0647841468F, -0.811536372F, -0.391260505F, -0.894502759F,
    -0.104818314F, 0.11602588F, -0.214319214F, 0.943933606F, -1.42478681F,
    1.53594267F, 1.19694924F, -0.947211564F, 0.55806905F, 2.51618052F,
    0.354892701F, 0.0910376608F, 1.59162402F, 0.573167443F, 1.14997447F,
    0.872636795F, 1.65094F, 0.302275687F, 1.37008631F, 0.164590031F,
    0.684084892F, 0.934599936F, 0.782874048F, -0.00370392599F, 0.299809217F,
    -0.14212124F, 0.333637565F, 0.555856526F, -1.08994651F, -0.978568F,
    -0.0566705912F, 0.632716775F, -1.95163214F, -0.765372813F, -0.394317806F,
    -1.38003361F, -0.517277718F, -1.15440285F, -1.52891648F, -0.501866341F,
    -0.39195171F, -1.80602717F, -0.321225852F, -1.6077491F, 0.182984754F,
    -1.69504476F, 1.12102973F, -0.811122894F, -1.32346046F, 0.314286917F,
    0.172392428F, 0.22136417F, 0.177017137F, 0.323637635F, 1.33155727F,
    -0.666876793F, 0.468926F, 2.30415511F, -0.143778265F, 1.08016694F,
    1.53535938F, 0.545212567F, 0.093782261F, 1.88903177F, 1.66532958F,
    0.257071853F, 0.900446594F, -0.324903965F, 1.8942982F, 0.8927266F,
    0.609891176F, -1.00978315F, 1.25305676F, 0.0594616793F, -0.329736233F,
    0.740882933F, -1.57412267F, 0.299193889F, -0.329574168F, -0.516647935F,
    -0.951243579F, -0.746399164F, -1.54562581F, -0.342752F, -1.0815258F,
    0.40066579F, -2.498703F, -1.14157391F, -1.12552404F, -0.57614851F,
    0.273376316F, -1.71328509F, -0.531674206F, -0.777255476F, -1.74377179F,
    1.36860669F, -0.118674934F, -1.30180013F, 0.829469562F, -0.0654933304F,
    -0.321396619F, 0.798297346F, 0.685990274F, 0.463189542F, 1.107867F,
    0.163232729F, 0.999880195F, 0.168688118F, 0.01441231F, 1.00503F,
    -0.220617607F, 0.838119805F, 0.868046045F, 0.776395202F, 1.1059736F,
    0.341875434F, 0.664525F, 2.07828879F, 0.497903377F, 1.16494346F, 1.01643562F,
    0.340508431F, 0.444224954F, 2.0459609F, 0.628412F, 0.459347099F,
    -0.045910202F, 0.190839201F, 0.964773059F, -0.0566110164F, 0.461595923F,
    -1.20988011F, 0.408044308F, -0.590389132F, -0.037426658F, -0.933553874F,
    -0.746440113F, -0.917507648F, -0.71860379F, -1.19626486F, -0.245720461F,
    -1.7253828F, -0.230668783F, -1.88603449F, -0.551454306F, -0.650510192F,
    -1.21012139F, -1.09316492F, -0.576460481F, 0.166752428F, -0.273031592F,
    -1.87815332F, 0.129745111F, -0.124916092F, 0.801281035F, 0.134157836F,
    0.389440477F, -1.49124026F, 1.57977188F, 1.15170133F, 0.567437947F,
    0.987318099F, 0.503941715F, 0.273947984F, 1.0242641F, 2.38043857F,
    0.527092278F, 0.152181849F, 1.12721932F, 1.48361695F, 0.569245338F,
    1.68511963F, -1.03586733F, 1.43736529F, 0.346565902F, 1.51088631F,
    -0.781356335F, 0.0615534931F, -0.087686196F, 0.105708167F, 0.103707239F,
    -0.292962253F, -1.37866557F, -0.0225361735F, -1.1047591F, 0.104622722F,
    -2.02277255F, 0.225524575F, -2.27879F, -0.187355176F, -0.356416553F,
    -1.92820358F, -1.11781263F, -0.693286777F, -0.456645459F, -1.1099329F,
    -0.494245261F, -0.814963043F, -0.823830545F, 0.0440332107F, -0.20948422F,
    0.307893574F, -0.769026756F, -1.04546928F, 2.98305798F, -1.02749848F,
    0.470627844F, 0.864403188F, 0.0903465897F, 1.16200233F, 1.19118786F,
    0.737006366F, 1.89398682F, -1.30650043F, 2.1648767F, 1.8944602F,
    0.227730975F, 0.602808416F, 1.27216947F, 0.700976729F, 0.774181128F,
    0.820887208F, -0.123798549F, 0.254129648F, 1.23671401F, -0.273307145F,
    0.368870378F, -1.22050774F, 0.108314663F, -0.295223266F, 0.727710366F,
    -2.01969337F, -0.952681482F, 0.521724701F, -2.23177552F, -0.559074402F,
    0.711146474F, -2.68471169F, -1.46239817F, -0.778213203F, 0.274694413F,
    -0.959053814F, -2.01255178F, 0.0096162241F, -1.4191978F, -0.73672688F,
    0.377907038F, -0.447138906F, -0.464495748F, 0.405071586F, -1.35976052F,
    -0.14808929F, 2.03395867F, -0.0168881379F, 0.560983121F, 0.243130341F,
    -0.162608966F, 1.33847535F, 1.14852571F, 1.43944168F, 1.26081038F,
    -0.531629324F, 1.4019568F, 1.31372929F, 0.82877481F, 1.01754987F,
    1.64131105F, 0.115735777F, -0.476928085F, 2.43397021F, -0.342183381F,
    0.429186046F, 0.230287F, 0.494969547F, 0.384988725F, -1.68838704F,
    0.0306526348F, 1.15567684F, -1.07068396F, -0.915881515F, -1.06009316F,
    -1.07166517F, 0.110040531F, -1.82754F, 0.471851826F, -1.04549873F,
    -3.0742321F, -0.422599167F, 0.210809946F, -1.26161253F, -0.652015388F,
    -1.26179516F, -0.9872334F, -0.824248552F, 0.534605324F, -0.644602239F,
    0.0972718149F, -1.49090946F, 0.787165165F, -0.532600045F, 2.0187602F,
    -0.564639866F, 0.187756881F, 0.134287208F, 1.74001503F, -0.030278774F,
    1.3644731F, 0.120387234F, 0.27557385F, 0.491612256F, 0.0848605111F,
    1.21112156F, 0.25608936F, 0.880388677F, 1.12680495F, 0.712403297F,
    1.05370224F, 0.34797135F, 1.75514829F, 1.40515494F, 0.0634519309F,
    1.08706403F, 0.992365539F, 0.707365513F, 1.09018183F, 0.117268659F,
    1.03271317F, -0.122047849F, 0.0610383898F, 0.425602466F, 0.641210914F,
    -0.169910103F, -1.33179545F, -0.279780507F, -0.620836198F, 0.767657399F,
    -0.501234531F, -2.44635773F, -0.568293F, -1.35886097F, 0.476641566F,
    -1.46537876F, -0.239624873F, -3.01244354F, -0.336836815F, -0.198402718F,
    -0.859129488F, -1.07322443F, -0.110345654F, -2.28406096F, 0.807445288F,
    -0.480115503F, -0.408856F, -0.364936978F, 0.999863386F, -0.979712725F,
    0.204749987F, 0.886212111F, 0.409199059F, 1.19781554F, -0.53425914F,
    1.58284247F, 0.721479774F, 1.35310018F, 0.113095522F, 1.05753517F,
    1.62383616F, 1.228315F, 0.647121608F, -0.0475636683F, 1.16539824F,
    1.83564603F, 0.908007F, 0.119435318F, -1.26534426F, 2.16969085F, 0.20125936F,
    0.323358238F, -0.285472393F, -0.987422884F, 0.480300248F, -0.202104449F,
    -0.0547787212F, -1.32036507F, -2.1562767F, 1.22266972F, -0.123299129F,
    -2.39445329F, -1.2651521F, -1.14647758F, 0.234414548F, -0.930143178F,
    -1.79821396F, -0.857544F, -1.38892961F, 0.256685346F, -0.450947136F,
    -1.34450758F, -0.880951703F, 0.189030439F, -0.544460714F, 0.315026343F,
    -0.150900722F, 0.465434641F, -0.329144984F, -0.509893417F, 1.8248862F,
    0.892358363F, 0.477675229F, 0.421226591F, 0.170371071F, 1.94821703F,
    0.448815286F, 1.42705894F, 1.04189396F, 1.01865578F, 0.24914819F,
    0.742493927F, 2.15974116F, 0.549623609F, -0.623066187F, 2.44750118F,
    -0.859004736F, -0.230756536F, 2.57456732F, -0.753996491F, -0.849466F,
    -0.876083136F, 1.90780139F, -1.04569101F, -1.16688883F, -0.00995842926F,
    -1.05588865F, -0.721525729F, -1.17491281F, -0.0354928F, -1.89746988F,
    -0.112320602F, -1.97724903F, -0.1549211F, -1.43612611F, -0.610838354F,
    -1.36431599F, -0.854723692F, 0.597348094F, -1.66252804F, -0.778727829F,
    -0.579689F, 1.05493546F, 0.0624605455F, -1.90981412F, 0.779823899F,
    1.06191874F, -0.21851036F, 0.868209779F, 0.0595060289F, 1.65881872F,
    0.311398745F, -0.0465783216F, 1.54612386F, 1.12848032F, 1.68246841F,
    0.612085164F, 0.195238978F, 0.962969363F, 1.62504673F, 0.455749869F,
    1.58906317F, 0.303372949F, 0.134558722F, 0.070134379F, 1.21000171F,
    1.32428205F, -1.64663768F, -0.103595503F, 1.02977884F, -0.657643676F,
    -0.237630904F, -0.718475044F, -0.7721228F, -1.00265932F, -0.138618484F,
    -0.538312256F, -1.20183671F, -1.99132335F, -0.000281540502F, -1.26016545F,
    -1.13175678F, -0.0913106203F, -1.30917203F, -2.42164016F, 0.931070089F,
    -0.981410384F, -0.488917917F, -1.23081803F, -0.117299639F, 0.254719079F,
    -0.402838528F, -0.536254823F, 1.19747865F, -0.973059654F, 1.37506509F,
    -0.104879878F, 0.593916714F, 1.66981637F, 0.346310109F, -0.00807121F,
    0.191243395F, -0.0650064126F, 1.07204068F, -0.349929661F, 1.40997672F,
    0.464540422F, -0.0479657315F, 1.50045812F, 1.65451491F, 0.829367876F,
    -0.537234426F, 2.38175511F, 0.283988804F, 1.3453536F, 1.04386675F,
    1.05747151F, 0.11562717F, 1.20773566F, 0.21695137F, 0.366763622F,
    0.634821296F, 1.67991173F, -2.24850893F, 1.31968415F, -0.66167742F,
    -0.0579200536F, -0.174838737F, -0.0467120558F, -1.65534163F, -0.694674432F,
    -0.139615849F, -0.974943638F, -0.883926749F, -0.904304F, -1.43345451F,
    -1.66165018F, 0.896102607F, -1.89038706F, -1.15438819F, -1.03132069F,
    -0.513247669F, -0.638828397F, -0.0676635802F, -0.850735366F, -1.62613952F,
    0.802830696F, 0.216358542F, 0.0455347523F, -0.497289479F, 0.0266858153F,
    1.16660571F, 0.128592357F, -0.00444556214F, 1.72631788F, 1.3634665F,
    -0.843551F, 1.47646832F, 1.12773049F, 1.10110486F, 1.07644725F, 0.805651188F,
    1.39135301F, 0.67228204F, -0.588344216F, 2.75685215F, 0.192418218F,
    1.24258924F, -1.04208028F, 1.20944178F, 0.235857517F, -0.578601122F,
    1.68363059F, -1.21158266F, -0.311202884F, -0.25585717F, -0.532824039F,
    -1.32298338F, 0.950216293F, -1.48015738F, -1.332183F, -1.0832454F,
    -0.479518354F, -1.29393363F, 0.141922638F, -1.86083281F, -1.74016798F,
    -0.873462558F, 0.84056282F, -1.90687609F, -0.233297914F, -1.62521601F,
    0.299378902F, -1.03408039F, 0.422131687F, 0.526323736F, -1.23585951F,
    0.0920122638F, 0.359116554F, 1.3125937F, -0.123637535F, 0.716805875F,
    0.511077464F, 0.461898267F, 1.45527554F, 0.834392428F, 1.29030406F,
    0.672999382F, 0.356544852F, 1.03183532F, 2.32159472F, 0.565419078F,
    -0.359208643F, 1.50745642F, 0.978462696F, 0.379421175F, 0.583143175F,
    -0.165619493F, 1.06755817F, -0.123750784F, 0.376376957F, -1.60720396F,
    0.7324633F, 0.648349881F, -2.24641776F, 0.32846716F, -0.955955863F,
    -0.787009F, -0.701503277F, -0.644477487F, -2.53331041F, 0.537257254F,
    -0.5282197F, -2.101161F, -0.805510759F, -1.40762317F, -0.136459678F,
    -0.211130008F, -1.83272135F, -0.182821393F, -0.673936784F, 0.243884489F,
    -0.93816489F, -0.529203475F, 0.815861285F, 0.456979245F, 0.0213650111F,
    -0.297430962F, 0.248434857F, 1.06086683F, 1.78533804F, 0.318954438F,
    0.0585455187F, 0.379907459F, 2.23509526F, 1.07221138F, 0.723374546F,
    0.777494788F, 0.955882192F, 0.646307F, 0.952431619F, 2.14873242F,
    -0.598156214F, -0.0553028882F, 1.82126975F, 0.100792609F, 0.363282681F,
    -0.265203357F, -0.160151199F, 0.214635298F, -0.251928866F, -0.797985315F,
    0.402014524F, -0.660898328F, -1.91945791F, -0.457098812F, 0.00960913487F,
    -1.38463426F, -0.89472729F, -1.06491888F, -1.26221144F, -1.00925505F,
    -0.36140573F, -0.96837157F, -1.55663645F, -0.551673353F, -0.444438487F,
    -0.441307217F, -0.745622933F, -0.987435222F, 0.508365035F, -0.304285765F,
    0.310064226F, -0.311166734F, 0.0521675199F, 0.761428237F, 0.45525676F,
    0.784388F, -0.0610065423F, 2.18045235F, -0.114894763F };

    __attribute__ ((section(".heapsram"))) static const float fv1[18] = { 6.24191159E-7F, 1.0F, 1.0F, 1.24838232E-6F,
    2.0F, 2.0F, 6.24191159E-7F, 1.0F, 1.0F, 1.0F, 1.0F, 1.0F, -1.65053844F,
    -1.72377622F, -1.86728549F, 0.682874441F, 0.757546961F, 0.903867841F };

    __attribute__ ((section(".heapsram"))) static const float fv2[16] = { 8.14942F, 8.14925766F, 0.431659639F, 0.431651F,
    8.14940834F, 8.14924622F, 0.431659579F, 0.431650937F, 8.14943314F,
    8.14927101F, 0.431658894F, 0.431650251F, 8.14948559F, 8.14932346F,
    0.431659311F, 0.431650668F };


/////////////////////////////////////////////////////////
// subfunctions
/////////////////////////////////////////////////////////

void mlButter(const float SOS[18], const float sig[200], float filt[200])
{
  int i;
  float tout;
  int ixy;
  float z[6];
  int iz;
  float tin;
  int isect;

  ixy = 0;
  tout = 0.0F;
  for (i = 0; i < 6; i++) {
    z[i] = 0.0F;
  }

  for (i = 0; i < 200; i++) {
    iz = 1;
    tin = sig[ixy];
    for (isect = 0; isect < 3; isect++) {

      tout      = z[iz - 1] + tin * SOS[isect];
      z[iz - 1] = (z[iz] + tin * SOS[3 + isect]) - tout * SOS[12 + isect];
      z[iz]     = tin * SOS[6 + isect] - tout * SOS[15 + isect];

      iz += 2;
      tin = tout;
    }

    filt[ixy] = tout;
    ixy++;
  }
}

float sum(const float x[200])
{
  float y;
  int k;
  y = x[0];
  for (k = 1; k < 200; k++) {
    y += x[k];
  }

  return y;
}


float var(const float x[200])
{
  float y;
  int ix;
  float xbar;
  int k;
  float r;
  ix = 0;
  xbar = x[0];
  for (k = 0; k < 199; k++) {
    ix++;
    xbar += x[ix];
  }

  xbar = fDiv(xbar,200.0F);
  ix = 0;
  r = x[0] - xbar;
  y = r * r;
  for (k = 0; k < 199; k++) {
    ix++;
    r = x[ix] - xbar;
    y += r * r;
  }

  y = fDiv(y,199.0F);
  return y;
}


boolean_T checkRes(const float check[2], const float golden[4])
{
  int k;
  boolean_T pass = true;

  for (k = 0; k < 2; k++) {
    pass = pass && (check[k] <= golden[k << 1]);
    pass = pass && (check[k] >= golden[1 + (k << 1)]);
  }

  return pass;
}

/////////////////////////////////////////////////////////
// main testing function 
/////////////////////////////////////////////////////////
int main(int argc, const char * const argv[])
{
  (void)argc;
  (void)argv;

  boolean_T pass;
  int coreid, k;
  float filt[200];
  float tmp[2];



  /////////////////////////////////////////////////////////
  // main test loop 
  // each core loops over a kernel instance
  /////////////////////////////////////////////////////////
  
  coreid = get_core_id();

  printf("starting %d kernel iterations... (coreid = %d)\n",KERNEL_ITS,coreid);

  if (coreid>3)
    coreid=coreid-4;

  synch_barrier();

  perf_begin();
  
  for(k = 0; k < getKernelIts(); k++)
  {
    // matlab kernel
    mlButter(fv1, *(float (*)[200])&fv0[200 * coreid], filt);
  }

  synch_barrier();

  perf_end();

  /////////////////////////////////////////////////////////
  // check results
  /////////////////////////////////////////////////////////

  synch_barrier();


  tmp[0] = sum(filt);
  tmp[1] = var(filt);
  pass   = checkRes(tmp, *(float (*)[4])&fv2[coreid << 2]);
  
  flagPassFail(pass, get_core_id());

/////////////////////////////////////////////////////////
// synchronize and exit
/////////////////////////////////////////////////////////

  return !pass;
}

